#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/shm.h>

#define BUFFER_LEN 10

struct Buffer
{
	int value[BUFFER_LEN];
    int producer_index;
    int customer_index;
    int flag;
};

int main(int argc, char const *argv[])
{
    int i;
    void *shm = NULL;

    // 信号量
    sem_t *empty = sem_open("/empty08", O_CREAT | O_EXCL, 0666, BUFFER_LEN);
    if (empty == SEM_FAILED)
    {
        perror("ERROR:"); // e.g. "ERROR: Permission denied" or similar
        exit(1);
    }

    sem_t *full = sem_open("/full08", O_CREAT | O_EXCL, 0666, 0);
    if (full == SEM_FAILED)
    {
        perror("ERROR:"); // e.g. "ERROR: Permission denied" or similar
        exit(1);
    }
    sem_t *mutex = sem_open("/mutex08", O_CREAT | O_EXCL, 0666, 1);
    if (mutex == SEM_FAILED)
    {
        perror("ERROR:"); // e.g. "ERROR: Permission denied" or similar
        exit(1);
    }
    
    int shmid = shmget(233, 4096, 0666|IPC_CREAT);
    if (shmid == -1)
    {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }
    
    shm = shmat(shmid, 0, 0);
    if (shm == (void *)-1)
    {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }

    printf("\nMemory attached at %X\n", (int)shm);

    struct Buffer* buffer = (struct Buffer*)shm;
    buffer->customer_index = 0;
    buffer->producer_index = 0;
    buffer->flag = 0;

    for (i = 0; i < 500; i++)
    {
        sem_wait(empty);
        sem_wait(mutex);

        //   如果发生消费, 进行数组规整
        if (buffer->customer_index != 0)
        {
            int j;
            for (j=0; j < buffer->producer_index - buffer->customer_index; j++)
            {
                buffer->value[j] = buffer->value[j+buffer->customer_index];
            }
            buffer->producer_index = buffer->producer_index - buffer->customer_index;
            buffer->customer_index = 0;
        }
        
        buffer->value[buffer->producer_index] = i;
        buffer->producer_index++;
        printf("produce %d\n", i);
        fflush(stdout);

        sem_post(mutex);
        sem_post(full);

        sleep(1);
    }
    buffer->flag = 1;

    // 把共享内存从当前进程中分离
    if (shmdt(shm) == -1)
    {
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }

    sem_close(empty);
    sem_close(full);
    sem_close(mutex);

    return 0;
}
